﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AutomatasPrj
{
    class DeltaAFND
    {
        Dictionary<Estado, Dictionary<char, HashSet<Estado>>> delta;

        public DeltaAFND()
        {
            this.delta = new Dictionary<Estado, Dictionary<char, HashSet<Estado>>>();
        }

        public void AddValue(Estado estadoIn, Char simbolo, Estado estadoOut)
        {
            if (!delta.ContainsKey(estadoIn))
                this.delta[estadoIn] = new Dictionary<char, HashSet<Estado>>();

            if (!delta[estadoIn].ContainsKey(simbolo))
                this.delta[estadoIn][simbolo] = new HashSet<Estado>();

            this.delta[estadoIn][simbolo].Add(estadoOut);
        }

        public void AddValues(DeltaAFND other)
        {
            foreach (KeyValuePair<Estado, Dictionary<char, HashSet<Estado>>> kvp in other.delta)
            {
                this.delta.Add(kvp.Key, kvp.Value);
            }
        }

        public HashSet<Estado> Evaluate(Estado estado, char simbolo)
        {
            // Listas vacias en no determinismo
            if (!delta.ContainsKey(estado)) return new HashSet<Estado>();
            if (!delta[estado].ContainsKey(simbolo)) return new HashSet<Estado>();

            return delta[estado][simbolo];
        }

        public HashSet<Estado> ClausuraEpsilon(Estado q)
        {
            if (this.Evaluate(q, '\0').Count() == 0)
                return new HashSet<Estado>();

            HashSet<Estado> epsilonReachable = this.Evaluate(q, '\0');

            HashSet<Estado> result = new HashSet<Estado>() { q };

            foreach (Estado r in epsilonReachable)
            {
                result.UnionWith(ClausuraEpsilon(r));
            }

            result.UnionWith(epsilonReachable);

            return result;
        }

        public HashSet<Estado> ClausuraEpsilon(HashSet<Estado> s)
        {
            HashSet<Estado> result = new HashSet<Estado>();

            // Inicialmente todos los del argumento
            result.UnionWith(s);

            HashSet<Estado> aux = new HashSet<Estado>();

            // Recursivamente sobre esos
            foreach (Estado q in result)
            {
                aux.UnionWith(ClausuraEpsilon(q));
            }

            result.UnionWith(aux);

            return result;
        }

    }
}
